export default class Roaming {
  /**
   *Creates an instance of Roaming.
   * @param {*} Cesium 需要传入
   * @param {*} viewer 需要传入
   * @param {*} options.modeluri 模型的uri 需要传入
   * @param {*} options.time 漫游时间  需要传入
   * @param {*} options.start 开始节点 不需要传入
   * @param {*} options.stop  结束节点 不需要传入
   * @param {*} options.Lines  点集合 需要传入
   * @param {*} options.isPathShow 路径是否显示 需要传入
   * @param {*} options.isfirstPerson 是否第一人称 需要传入
   * @memberof Roaming
   */
  constructor(viewer, options) {
    this.Cesium = options.Cesium;
    this.viewer = viewer;
    this.flyEntity = undefined;
    this.url = options.modeluri;
    this.time = options.time;
    this.start = undefined;
    this.stop = undefined;
    this.Lines = options.Lines;
    this.isPathShow = options.isPathShow;
    this.isfirstPerson = options.isfirstPerson;
    this.isModelShow = options.isModelShow;

    this.property = this.ComputeRoamingLineProperty(
      options.Lines,
      options.time,
      options.start
    );
    this.InitRoaming(
      this.property,
      this.start,
      this.stop,
      this.isPathShow,
      this.isModelShow
    );
  }
  /**
   *
   *
   * @param {*} Lines 点集合
   * @param {*} time 漫游时间
   * @param {*} start 开始时间节点
   * @returns
   * @memberof Roaming
   */
  ComputeRoamingLineProperty(Lines, time) {
    let property = new this.Cesium.SampledPositionProperty();
    let lineLength = Lines.length;
    let tempTime = time - (time % lineLength);
    let increment = tempTime / lineLength;
    let start = this.Cesium.JulianDate.now();
    this.start = start;
    let stop = this.Cesium.JulianDate.addSeconds(
      start,
      tempTime,
      new this.Cesium.JulianDate()
    );
    this.stop = stop;
    this.viewer.clock.startTime = start.clone();
    this.viewer.clock.stopTime = stop.clone();
    this.viewer.clock.currentTime = start.clone();
    this.viewer.clock.clockRange = this.Cesium.ClockRange.CLAMPED; // 达到终止时间后停止
    this.viewer.clock.multiplier = 10;

    for (let i = 0; i < lineLength; i++) {
      let time = this.Cesium.JulianDate.addSeconds(
        start,
        i * increment,
        new this.Cesium.JulianDate()
      );
      let position = Lines[i];
      property.addSample(time, position);
    }
    return property;
  }
  /**
   *
   *
   * @param {*} position computeRoamingLineProperty计算的属性
   * @param {*} start 开始时间节点
   * @param {*} stop 结束时间节点
   * @param {*} isPathShow path路径是否显示
   * @param {*} isModelShow Model路径是否显示
   * @memberof Roaming
   */
  InitRoaming(position, start, stop, isPathShow, isModelShow) {
    this.flyEntity = this.viewer.entities.add({
      availability: new this.Cesium.TimeIntervalCollection([
        new this.Cesium.TimeInterval({
          start: start,
          stop: stop
        })
      ]),
      // 位置
      position: position,
      // 计算朝向
      orientation: new this.Cesium.VelocityOrientationProperty(position),
      // 加载模型
      model: {
        // 模型路径
        uri: this.url,
        // 模型最小刻度
        minimumPixelSize: 64,
        maximumSize: 128,
        // 设置模型最大放大大小
        maximumScale: 200,
        // 模型是否可见
        show: true,
        // 模型轮廓颜色
        silhouetteColor: this.Cesium.Color.WHITE,
        // 模型颜色  ，这里可以设置颜色的变化
         color: isModelShow?undefined:new this.Cesium.Color(0.0, 0.0, 0.0, 0.0),
        // 仅用于调试，显示魔仙绘制时的线框
        debugWireframe: false,
        // 仅用于调试。显示模型绘制时的边界球。
        debugShowBoundingVolume: false,

        scale: 20,
        runAnimations: true // 是否运行模型中的动画效果
      },
      path: {
        resolution: 1,
        material: new this.Cesium.PolylineGlowMaterialProperty({
          glowPower: 0.1,
          color: this.Cesium.Color.YELLOW
        }),
        width: 10,
        show: isPathShow
      }
    });
    this.flyEntity.position.setInterpolationOptions({
      // 点插值
      interpolationDegree: 5,
      interpolationAlgorithm: this.Cesium.LagrangePolynomialApproximation
    });
    this.viewer.trackedEntity = this.flyEntity;
    if (this.isfirstPerson) {
      this.addSceneEvent(time => {
        this.getRoamingPosition(time);
      });
    }
  }
  /**
   *漫游的暂停和继续
   *
   * @param {*} state bool类型 false为暂停，ture为继续
   * @memberof Roaming
   */
  PauseOrContinue(state) {
    if (state) {
      // 继续播放
      if (!this.handler && this.entity) {
        this.addSceneEvent(time => {
          this.getRoamingPosition(time);
        });
      }
    } else {
      if (this.handler) {
        // 停止监听屏幕绘制事件(停止相机变化)
        this.handler();
        this.handler = null;
        // 解锁相机视角
        this.viewer.camera.lookAtTransform(this.Cesium.Matrix4.IDENTITY);
      }
      if (this.clockStopHander instanceof Function) {
        this.clockStopHander();
        this.clockStopHander = null;
      }
    }
    this.viewer.clock.shouldAnimate = state;
  }

  /**
   *
   * @param {是否显示漫游路径} state
   */
  ShowPath(state) {
    this.flyEntity.path.show = state;
  }

  /**
   *
   * @param {是否显示模型} state
   */
  ShowModel(checked) {
    if (checked) {
      this.flyEntity.model.color = undefined;
    } else {
      this.flyEntity.model.color = new this.Cesium.Color(0.0, 0.0, 0.0, 0.0);
    }
    this.viewer.trackedEntity = this.flyEntity;
  }
  /**
   * 是否启用第一人称
   * @param {*} state
   */
  FirstPerson(state) {
    if (state) {
      this.addSceneEvent(time => {
        this.getRoamingPosition(time);
      });
    } else {
      if (this.handler) {
        // 停止监听屏幕绘制事件(停止相机变化)
        this.handler();
        this.handler = null;
        // 解锁相机视角
        //this.viewer.camera.lookAtTransform(this.Cesium.Matrix4.IDENTITY);
      }
    }
  }
  /**
   *改变飞行的速度
   *
   * @param {*} value  整数类型
   * @memberof Roaming
   */
  ChangeRoamingSpeed(value) {
    this.viewer.clock.multiplier = value;
  }
  /**
   *
   *取消漫游
   * @memberof Roaming
   */
  EndRoaming() {
    if (this.flyEntity !== undefined) {
      this.viewer.entities.remove(this.flyEntity);
    }
    if (this.handler) {
      // 停止监听屏幕绘制事件(停止相机变化)
      this.handler();
      this.handler = null;
      // 解锁相机视角
      // this.viewer.camera.lookAtTransform(this.Cesium.Matrix4.IDENTITY);
    }
  }

  /**
   * 监听场景渲染事件
   * @param callback
   */
  addSceneEvent(callback) {
    // addEventListener() → Event.RemoveCallback
    // 监听之前先销毁
    if (this.handler instanceof Function) {
      this.handler();
      this.handler = null;
    }
    this.handler = this.viewer.scene.preRender.addEventListener(
      (scene, time) => {
        callback(time);
      }
    );
  }

  addClockEvent(callback) {
    if (this.clockStopHander instanceof Function) {
      this.clockStopHander();
      this.clockStopHander = null;
    }
    this.clockStopHander = this.viewer.clock.onStop.addEventListener(time => {
      callback();
    });
  }

  /**
   * 根据时刻获取漫游位置
   * @param {object} time
   * @memberof Roaming
   */
  getRoamingPosition(time) {
    if (this.flyEntity) {
      const position = this.flyEntity.position.getValue(time);
      this.setCameraPosition(position, this.view || {});
    }
  }

  /**
   * 设置相机位置
   * @param {cartesian3} position
   * @param {object} options
   * @memberof Roaming
   */
  setCameraPosition(position, options) {
    if (position) {
      // 最新传进来的坐标（后一个位置）
      this.position2 = this.cartesian3ToWGS84(position);
      let heading = 0;
      // 前一个位置点位
      if (this.position1) {
        // 计算前一个点位与第二个点位的偏航角
        heading = this.bearing(
          this.position1.latitude,
          this.position1.longitude,
          this.position2.latitude,
          this.position2.longitude
        );
      }
      this.position1 = this.cartesian3ToWGS84(position);
      if (position) {
        const dynamicHeading = this.Cesium.Math.toRadians(heading);
        const pitch = this.Cesium.Math.toRadians(options.pitch || -20.0);
        const range = options.range || 2000.0;
        this.viewer.camera.lookAt(
          position,
          new this.Cesium.HeadingPitchRange(dynamicHeading, pitch, range)
        );
      }
    }
  }

  /**
   * @name bearing 计算两点的角度 heading
   * @param startLat 初始点的latitude
   * @param startLng 初始点的longitude
   * @param destLat 第二个点的latitude
   * @param destLng 第二个点的latitude
   * @return {number} heading值
   */
  bearing(startLat, startLng, destLat, destLng) {
    startLat = this.Cesium.Math.toRadians(startLat);
    startLng = this.Cesium.Math.toRadians(startLng);
    destLat = this.Cesium.Math.toRadians(destLat);
    destLng = this.Cesium.Math.toRadians(destLng);
    const y = Math.sin(destLng - startLng) * Math.cos(destLat);
    const x =
      Math.cos(startLat) * Math.sin(destLat) -
      Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng);
    const brng = Math.atan2(y, x);
    const brngDgr = this.Cesium.Math.toDegrees(brng);
    return (brngDgr + 360) % 360;
  }

  /**
   * cartographic 转Degrees下地理坐标
   * @param point radius下的WGS84坐标
   * @return degrees下的WGS84坐标
   */
  cartesian3ToWGS84(point) {
    const cartographic = this.Cesium.Cartographic.fromCartesian(point);
    const lat = this.Cesium.Math.toDegrees(cartographic.latitude);
    const lng = this.Cesium.Math.toDegrees(cartographic.longitude);
    const alt = cartographic.height;
    return {
      longitude: lng,
      latitude: lat,
      height: alt
    };
  }
}
